'''
Created on Mar 14, 2011

@author: mwarren1
'''
import re
import socket
import email
import imaplib
import socks

import maildroplibs

from wx.tools.dbg import Logger
    
debug = Logger('connector')
debug.SetStream(maildroplibs.DEBUGSTREAM)
debug(enable = maildroplibs.ENABLEDEBUG)
    
def stop():
    ImapConnector.STOP = True
    
    debug("Instances Running: " + str(ImapConnector.instanceList))
    for connector in ImapConnector.instanceList:
        connector.__del__()
 

class ImapConnector(object):
    '''
    classdocs
    '''
    
    STOP = False
    instanceList = []
    
    __initSocket = None 

    def __init__(self, settings):
        '''
        Constructor
        '''
        self.settings = settings
        
        self.__class__.instanceList.append(self)
    
    def __del__(self):
        if (not self.__class__.STOP):
            debug("Deleting ImapConnector " + str(self))
        if (self.__class__.instanceList.count(self) > 0):
            self.__class__.instanceList.remove(self)
           
    def connect(self):
        
        try:
            self.settings.verify()
        except maildroplibs.SettingsError as e:
            e.showError()
            return False
        
        proxysetting = self.settings['PROXY']
        proxyenabled = self.settings['IMAPPROXYENABLED']
        proxytype = self.settings['IMAPPROXYTYPE']
        proxyurl = self.settings['IMAPPROXYURL']
        proxyport = self.settings['IMAPPROXYPORT']
        proxyuname = self.settings['IMAPPROXYUSERNAME']
        proxypword = self.settings.getimapproxypassword()
        ssl = self.settings['SSL']
        server = self.settings['EMAILSERVER']
        imapsslport = self.settings['IMAPSSLPORT']
        imapport = self.settings['IMAPPORT']
        username = self.settings['USERNAME']
        pword = self.settings.getpassword()
        
        
        if self.__class__.__initSocket is None:
                self.__class__.__initSocket = socket.socket
        
        if ((not self.__class__.STOP) and proxyenabled and proxysetting == maildroplibs.PROXY_MAN):
            socks.setdefaultproxy(proxytype=proxytype, addr=proxyurl, port=proxyport, username=proxyuname, password=proxypword)
            socket.socket = socks.socksocket
        elif not self.__class__.STOP:
            socket.socket = self.__class__.__initSocket
        
        try:
            if ((not self.__class__.STOP) and ssl):
                self.imap = imaplib.IMAP4_SSL(server, imapsslport)
            elif (not self.__class__.STOP):
                self.imap = imaplib.IMAP4(server, imapport)
            print "Connected to email server"
        except Exception as e:
            print e
            debug(str(e))
            return False
            
        
        if (not self.__class__.STOP):    
            
            print "Logging in..."
            debug(str(self.imap.login(username, pword)))
        
        return True

    def getMessages(self, label = None):
        messageList = []
        
        if label is None:
            label = self.settings['EMAILLABEL']
        
        if (not self.__class__.STOP):
            folderlist = self.imap.list()
            hasFolder = False
            for folder in folderlist[1]:
                if folder.find('"'+label+'"') > 0:
                    hasFolder = True
                    debug(str(folder))
                    break
        
        if (not self.__class__.STOP) and not hasFolder:
            print label + " Not Found!"
            debug(label + ' Not Found!')
            
        if ((not self.__class__.STOP) and hasFolder):
            debug(label + " found")
            self.imap.select(label)
            print str(self.__getMessageCount(label)) + " Messages found in " + label
            debug(str(self.__getMessageCount(label)) + " Messages found in " + label)  
              
            status = self.imap.status(label, '(MESSAGES)')
            if(status[0] == "OK"):
                match = re.match(r"\""+label+"\" \(MESSAGES (?P<NUM>\d+)\)", status[1][0])
                if (match == None) and (not self.__class__.STOP):
                    debug("Match not found!")
                    
        if ((not self.__class__.STOP) and hasFolder):
            count = self.__getMessageCount(label)
            if count > 0:
                print "Reading %s Messages..." % count
                debug("Reading %s Messages..." % count)
            
                for i in range(count):
                    if (not self.__class__.STOP):
                        print "Downloading Files From Message %s" % str(i+1)
                        debug("Downloading Files From Message %s" % str(i+1))
                        typ, data = self.imap.fetch(i+1, '(RFC822)')
                        if (typ == 'OK') and (not self.__class__.STOP):
                            msg = email.message_from_string(data[0][1])
                            messageList.append(msg)
                        elif (not self.__class__.STOP):
                            print 'Message Parser Failed: ' + str(typ)
                            debug('Message Parser Failed: ' + str(typ))
                print
        if (not self.__class__.STOP):
            return messageList
  
    def getMessageHeaders(self, label = None):
        if (not self.__class__.STOP):
            if label is None:
                label = self.settings['EMAILLABEL']
            messageList = []
            count = self.__getMessageCount(label)
            print "Reading %s Messages..." % count
            for i in range(count):
                if (not self.__class__.STOP):
                    print "Reading Message %s" % str(i+1)
                    typ, data = self.imap.fetch(i+1, '(RFC822.HEADER UID RFC822.SIZE)')
                    if (typ == 'OK') and (not self.__class__.STOP):
                        print data
                        msg = email.message_from_string(data[0][1])
                        for part in msg.walk():
                            print part.keys()
                            print part.get('To')
                            print part.get('From')
                            print part.get('Date')
                            print part.get('Subject')
                        messageList.append(msg)
                    else:
                        print 'Message Parser Failed: ' + typ
            print
  
    def clearMessages(self, label, keepList = None):
        if (not self.__class__.STOP):
            if label is None:
                label = self.settings['EMAILLABEL']
            print "Deleting Messages..."
            count = self.__getMessageCount(label)
            deleteRange = range(1, count+1)
            debug("Initially deleting messages " + str(deleteRange))
            
            if keepList is not None:
                debug("Keeping Messages: " + str(keepList))
                messageDict = {}
                keepNums = []
                for num in range(1, count+1):
                    typ, data = self.imap.fetch(num, '(BODY[HEADER.FIELDS (MESSAGE-ID)])')
                    if typ == 'OK':
                        message_num = re.search(r'(\d+) \(BODY.*', data[0][0])
                        message_id = re.search(r'(<.*>)', data[0][1])
                        messageDict[message_id.group(1)] = int(message_num.group(1)) 
                for message in keepList:
                    if 'message-id' in message:
                        messageID = str(message['message-id'])
                        messageNum = messageDict[messageID]
                        debug("Keeping Message #" + str(messageNum) + ", message id: " + messageID)
                        keepNums.append(messageNum)
                
                for num in keepNums:
                    if num in deleteRange:
                        deleteRange.remove(num)
                debug("After keepList, deleting messages " + str(deleteRange))

            for num in deleteRange:
                if (not self.__class__.STOP):
                    print 'Deleting Message %s' % num
                    self.imap.store(num, '+FLAGS', '\Deleted')
            if self.imap.state == 'SELECTED':
                self.imap.expunge()
            else:
                debug("Could not delete messages")
                debug("Command EXPUNGE illegal in state " + str(self.imap.state) + ", only allowed in state SELECTED")
        
       
    def disconnect(self):     
        response =str(self.imap.logout())         
        if (not self.__class__.STOP): 
            debug(response)
            print "Logging out..."
        
        
    def __getMessageCount(self, label):
        try:
            self.settings.verify()
            if self.imap.select(label)[0] == 'NO':
                return 0
            return int(self.imap.select(label)[1][0])
        except maildroplibs.SettingsError as e:
            if (not self.__class__.STOP):
                e.showError()
            return 0
        
        